'''
The module overrides Python's socket module.

@author: Hatem Oraby
'''
import socket
import errno
import time
from heapq import heappush, heappop
from copy import copy
import random
import logging

#from twisted.internet.abstract import isIPAddress
from twistedSim.Scheduler import SchedulerSingleton
from twistedSim import simConfig

#Globals----------
Scheduler = SchedulerSingleton
originalSocket = socket #Keep track of the original socket
sendDelayRndmProfile = random.Random(simConfig.Network._seedSendDelay) #Bad design
portGenerationRndmProfile = random.Random(simConfig.Network._seedPortGeneration)
loggingThreshold = logging.CRITICAL#Change to logging.DEBUG for verbosity 
_remoteProcess = False#Indicates whether or not we running on a remote node.
                      #Equals to True if this simulation is process-based.
_proxy = None #In process based, this variable will be set by the 
              # proxy to the proxy object itself.
#Globals END HERE---------------------------------------



#Special Functions & Classes --------------------------

class _specialClass:
    '''
    In many cases we need this class to chec
    '''
    pass

#The following function is going to be the logging function in a later
# time, for now its just a fast hack.
def log(text, level):
    if level > loggingThreshold:
        return 
    print text


def installModule():
    '''
    Override Python C{socket} module classes and functions.
    '''    
    import socket
    from twistedSim.overrideManager import OverrideManager
    
    OverrideManager.storeEntity(originalFn = originalSocket.socket,
                                   fullName = "socket.socket")
    #originalSocket.socket = serverSocket
    socket.socket = _SocketOverride
    
    OverrideManager.storeEntity(originalFn = originalSocket.gethostname,
                                   fullName = "socket.gethostname")
    #originalSocket.gethostname = gethostname
    socket.gethostname = gethostname
    
    OverrideManager.storeEntity(originalFn = originalSocket.gethostbyname,
                                   fullName = "socket.gethostbyname")
    #originalSocket.gethostbyname = gethostbyname
    socket.gethostbyname = gethostbyname
    
    OverrideManager.storeEntity(originalFn = originalSocket.error,
                                   fullName = "socket.error")
    #originalSocket.error = _socketError
    socket.error = _socketError
    

def isIPAddress(addr):
    """
    Copied from twisted.internet.abstract.
    
    Could have called it instead, but in case someone wanted to use
    this module only without using twisted then he would able to.
    
    Determine whether the given string represents an IPv4 address.

    @type addr: C{str}
    @param addr: A string which may or may not be the decimal dotted
    representation of an IPv4 address.

    @rtype: C{bool}
    @return: C{True} if C{addr} represents an IPv4 address, C{False}
    otherwise.
    """
    dottedParts = addr.split('.')
    if len(dottedParts) == 4:
        for octet in dottedParts:
            try:
                value = int(octet)
            except ValueError:
                return False
            else:
                if value < 0 or value > 255:
                    return False
        return True
    return False


#In python 2.5 socket.error doesn't inherit from IOError,
#selectReactor checks for IOError but not socket.Error
class _socketError(originalSocket.error, IOError):
    __init__ = originalSocket.error.__init__

def _getCurrentMachine():
    '''
    Returns the current active machine. If this node is a remote process
    then this method will return the proxy for the owning machine on this
    process.
    '''
    if not _proxy:
        from twistedSim.simManager import Machine
        return Machine.current
    else:
        return _proxy.machine
    
def _getCurrentModule():
    '''
    Returns the current active module. If this node is a remote process
    then this method will return the proxy for module object on this
    process.
    '''
    if not _proxy:
        from twistedSim.simManager import Module
        return Module.current
    else:
        return _proxy.module


class SocketErrors:
    '''
    An enumeration that stores socket errors in a friendly name.
    '''
    addressAlreadyInUse =  _socketError(errno.EADDRINUSE,'Address already in use') #10084
    socketTypeNotSupported = _socketError(errno.ESOCKTNOSUPPORT, 'Socket type not supported')#10044
    socketAlreadyConnected = _socketError(errno.EISCONN, 'Socket is already connected') #10056
    notListening = "Dummy error for not listening"
    notBound = "Dummy error for socket not bound"
    alreadyBound = _socketError(errno.EINVAL, 'Invalid argument')#10022
    listeningConnect = alreadyBound
    badDescriptor = _socketError(errno.EBADF , 'Bad file descriptor')#9
    noFileno = badDescriptor
    socketNotConnected = _socketError(errno.ENOTCONN, 'Socket not connected')#10057
    invalidArgument = alreadyBound
    integerRequired = TypeError, "an integer is required"
    blockingNotImplemented = "Simulation doesn't support blocking sockets yet"
    connectNonBlocking = _socketError(errno.EWOULDBLOCK,'The socket operation could not be completed without blocking')#10035
    nothingToAccept =  connectNonBlocking
    #alreadyTryingToConnect = "Error, i'm already trying to connect"  #socketNotConnected
    dontOwnAddress = _socketError(errno.EADDRNOTAVAIL,"Can't assign requested address")#10049
    nothingToReceive = connectNonBlocking
    #Make sure of the nothingToReceive error
    sendBufferFull = connectNonBlocking 
    connectionRefused = _socketError(errno.ECONNREFUSED,'Connection refused')#10061
    socketDisconnected = _socketError(errno.ECONNABORTED,'Software cause connection abort')#10053 #Where is the other error??
    operationNotSupported = _socketError(errno.EOPNOTSUPP,'Operation not supported')#10045
    messageTooLong = _socketError(errno.EMSGSIZE,'Message too long')#10040
    unreachable = _socketError(errno.ENETUNREACH, "Network is unreachable")#10051
    
    def typeError(self, methodName, argumentsNeeded, argumentsProvided):
        '''
        Produce a customized typeError exception string.
          
        I don't know how they raise the appropriate error so i 
        needed to make a work around.
        '''
        if argumentsNeeded == 0:
            args = "takes no arguments"
        elif argumentsNeeded == 1: 
            args = "takes exactly 1 argument"
        else:
            args = "takes exactly " + str(argumentsNeeded)+ " arguments"
            
        return TypeError, str(methodName) + '() ' + args+ ' '+ ' (' \
                            + str(argumentsProvided) + ' given)' 

#End of special functions & classes --------------------



class messageTypes():
    '''
    Since Python doesn't contain enumeration, so this class acts as an
    Enumeration that contains the possible sent messages types.
    '''    
    if loggingThreshold <= logging.DEBUG:
        HandShake_1 = "HandShake_1"
        HandShake_2 = "HandShake_2"
        HandShake_3 = "HandShake_3"
        
        ConnectionRefused = "ConnectionRefused"
        IPnotFound = "IpNotFound"
        
        Connect = "Connect"
        Disconnect = "Disconnect"
        
        Data = "Data"
    else:
        HandShake_1 = 0
        HandShake_2 = 1
        HandShake_3 = 2
        
        ConnectionRefused = 5
        IPnotFound = 6
        
        Connect = 10
        Disconnect = 11
        
        Data = 20


#TODO: Change the class name to capital 'S' --> SocketMessage
class socketMessage():
    '''
    A wrapper for data. It's used to send messages between emulated
    sockets.
    
    @type messaageType: L{messageTypes} attribute
    @param messageType: The type of the message to be sent.
    
    @type data: C{str}
    @param data: The data to be sent, though any data type will
        be accepted, only C{str} should be used.
    
    @type senderAddr: C{str}
    @param senderAddr: The IP of the sender.
    '''
    def __init__(self, dstAddr, messageType, sktType, data = None,
                 senderAddr = None, seq = None):
        self._dstAddr = dstAddr
        self._messageType = messageType
        self._data = data
        self._senderAddr = senderAddr
        self._seq = seq
        self._sktType = sktType

    def setData(self,data):
        '''
        @type data: C{str}
        '''
        self._data = data
        
    def getData(self):
        '''
        @rtype: C{str}
        @return: The data as a C{str} though it can be any object
            if the sender didn't send C{str}
        '''
        return self._data

    def setMessageType(self,messageType):
        '''
        @type messageType: L{messageTypes}
        '''
        self._messageType = messageType

    def getMessageType(self):
        '''
        @rtype: L{messageTypes}
        '''
        return self._messageType
    
    def setMessage(self, messageType, data):
        '''
        Set the message messageType and Data.
        
        @type messageType: L{messageTypes}
        @type data: C{str}
        '''
        self._messageType = messageType
        self._data = message
        
    def getMessage(self):
        '''
        Return the content of the message.
        
        @rtype: L{messageTypes},C{str}
        '''
        return self._messageType,self._data
    
    def setSenderAddr(self,addr):
        '''
        Set sender address
        
        @type addr: C{str}
        '''
        self._senderAddr = addr
    
    def getSenderAddr(self):
        '''
        Return sender's Address
        
        @rtype: C{str}
        '''
        return self._senderAddr
    
    
    def getDstAddr(self):
        '''
        Return destination's Address
        
        @rtype: C{str}
        '''
        return self._dstAddr
    
    def getSocketType(self):
        '''
        Return socket type.
        
        @rtype: C{int}
        '''
        return self._sktType
    
    def setSeq(self, seq):
        '''
        Sets the message sequence number for stream oriented protocols
        (e.g. TCP).
        
        @type seq: C{int}
        @param seq: The message's sequence.
        '''
        self._seq = seq
    
    def getSeq(self):
        '''
        Sets the message sequence number for stream oriented protocols
        (e.g. TCP).
        
        @rtype: C{int}
        '''
        return self._seq
    


def _networkModel(message, senderInterface, reciverInterface, network):
    '''
    When a message is being sent through the network, this function
    calculates the amount of delay that the message will experience
    until it reaches its destination address (if it exists).
    '''
    
    sockType  = message.getSocketType()
    dstIp = message.getDstAddr()[0]
    
    if dstIp == '127.0.0.1':
        delay, stdDev = SocketUtil.SendDelays[dstIp]
    else:
        delay, stdDev = SocketUtil.SendDelays[sockType]
    
    if not simConfig.Network.fixedSendDelay:
        delay = sendDelayRndmProfile.gauss(delay,stdDev)
        delay = abs(delay) #It could yield in negative values
    return delay

   
class Network:
    '''
    Represents a network. The class is also responsible for providing
    the functionalities that enables IP Interfaces (that belong to the
    same network) to send messages to each other. 
    
    Its recommended not to create a class of this class directly (unless
    you know what you are you doing). Instead, just create an IpInterface
    and specify its networkID to be the network ID that you want and the
    L{Network} object will be automatically created. 
    
    Each instance (i.e. Network object) contains a collection of IP
    interfaces. All the IP interfaces in the same L{Network} set can see
    and reach other.
    
    @type networkID: Anything, though an C{int} or C{str} preferred.
    @param networkID: The network ID.
    '''
    def __init__(self, networkID):
        self._ID = networkID
        self._interfaces = {}
    
    def getNetworkID(self):
        '''
        Contains the network ID.
        
        @rtype: Some object (usually C{int} or C{str}).
        @return: The network ID 
        '''
        return self._ID
    
    def addInterface(self, interface):
        '''
        Adds an IP Interface to the network.
        
        @type interface: L{IpInterface}
        @param interface: The IP Interface to be added.
        '''
        if interface.getIp() in self._interfaces:
            ValueError("An Interface with same IP already exists.")
        self._interfaces[interface.getIp()] = interface
        
    def removeInterface(self, interfaceIP):
        '''
        Remove an IP Interface from this network.
        
        @type interface: L{IpInterface}
        @param interface: The IP Interface to be removed.
        '''
        del self._interfaces[interfaceIP]

    def send(self, message, networkModel = _networkModel):
        '''
        Send a message across the network.
        
        @type message: L{SocketMessage}
        @param message: The message to be sent. The message sender
            and receiver attributes should be set.
            
        @type networkModle: C{Callable}
        @param networkModle: The function that will be called to 
            calculate the message send delay. If parameter is ignored
            then _networkModel function is called by default.
        '''
        dstIP = message.getDstAddr()[0]
        senderIP = message.getSenderAddr()[0]
        senderInterface = self._interfaces[senderIP]
        try:
            dstInterface = self._interfaces[dstIP]
        except KeyError:
                #TODO: Send back operation-timed out exception #10060
                raise NotImplementedError("Non-Existing Destination")
        else:
            senderInterface = self._interfaces[senderIP]
            delay = networkModel(message, senderInterface, dstInterface,
                                 self)
            
            if delay != None: #i.e do not drop the message.
                Scheduler.enqueue(delay, self._deliverMsg, message)
 

    def _deliverMsg(self, message):
        '''
        The method that do the actual message delivery when the delivery
        time comes.
        '''
        receiverIP = message.getDstAddr()[0]
        try:
            #The destination address might have died between the moment the
            # the message was sent and the moment it should be delivered 
            # in (i.e. now). So, check again to see if destination address
            # exists or not.
            receiverInterface = self._interfaces[receiverIP]
        except KeyError:
            #TODO: send back destination not found - operation timed out#10060
            raise NotImplementedError("Later: IP: "+str(recieverIp)+" not found" )
        
        if loggingThreshold <= logging.DEBUG:
            text  = "Delivering Message: \n"
            text += "Sender: " + str(message.getSenderAddr())
            text += "\tReceiver: " + str(message.getDstAddr())
            text += "\nMessageType: " + str(message.getMessageType())
            text += "\nPayLoad:\n"
            text += str(message.getData())
            text += "\n-----------END OF MESSAGE-------------"
            log(text, logging.DEBUG)
        receiverInterface.pushMsg(message)
    
    
    def sendConnRefused(self, sendingInterfaceIP, refusedMessage):
        '''
        Sends a connection refused message.
        
        If an IP Interface received a message and it found out that the
        message if directed to a port that is not being listened on, then
        the machine of that IP Interface might choose to send back to the
        sender a standard socket connection refused message.
        
        @type sendingInterfaceIP: C{str}
        @param sendingInterfaceIP: The IP of the interface sending the
            socket refused message.
        
        @type refusedMessage: L{socketMessage}
        @param socketMassage: The message that has been tried to be
            delievered but it was refused.
        '''
        sockType = refusedMessage.getSocketType()
        #Only reliable connections may get connection refused.
        if sockType != originalSocket.SOCK_DGRAM:
            #If the message that was failed to be delivered is a failed
            # connection notification then it has no origin and would
            # cause an infinite loop on the scheduler if it was resent.
            #Also, since a disconnect also doesn't have an ack (in our 
            # simulation and not in real life) then so we will also 
            # ignore such message.
            msgType = refusedMessage.getMessageType()
            if msgType != messageTypes.ConnectionRefused and \
               msgType != messageTypes.IPnotFound and \
               msgType != messageTypes.Disconnect:
                    senderAddr = refusedMessage.getSenderAddr()
                    newMsg = socketMessage(senderAddr,
                                           messageTypes.ConnectionRefused,
                                           sockType,
                                           None,
                                           refusedMessage.getDstAddr(),
                                           seq = 0)
                    self.send(newMsg)

class NetworksManager():
    '''
    A manager for all the networks created in the simulation process.
    L{Network}s should be created through this class, not through 
    instantiating a Network object class.  
    '''
    _allNetworks = {}
    defaultNetwork = 'internet'

    
    def networkCreateOrAppend(networkID, interface):
        '''
        Add to L{IpInterface} interface to L{Network} networkID, if 
        networkID doesn't exist then create it. The method finally
        returns the created network.
        
        IF the interface is the loop-back address (i.e 127.0.0.1)
        then a network is created but not added to the rest of
        global networks.
        
        @type interface: L{twistedSim.simManager.IpInterface}
        @param interface: The interface to be added. 
        '''
        if interface.getIp() == '127.0.0.1':
            network = Network('127.0.0.1')
        else:
            if networkID not in NetworksManager._allNetworks:
                NetworksManager._allNetworks[networkID] = Network(networkID)
            network = NetworksManager._allNetworks[networkID]
        network.addInterface(interface)
        return network
    networkCreateOrAppend = staticmethod(networkCreateOrAppend)



class IpInterface:
    '''
    Represents a network interface attached a machine.
   
    Though a single network interface can have more than one IP,
    for ease of configuration, an instance of this class represents
    only one IP. If more than IP is needed then a new interface
    should be instantiated.
   
    @type ip: C{str}
    @param ip: A valid IP string.
   
    @type machine: L{Machine}
    @param machine: The machine that the interface will be attached
        to.
       
    @type upBand: C{float}
    @param upBand: The upload bandwitdh for the interface.
        This variable is currently dummy.
       
    @type downBand: C{float}
    @param downBand: The download bandwitdh for the interface.
        This variable is currently dummy.
   
    @type sendBuffer: C{int}
    @param sendBuffer: Default send buffer to be used with
        interface. This attribute may move to machine attribute
        if it turned out to be a platform dependent rather than
        interface dependent.
        This variable is currently dummy.
       
    @type recvBuffer: C{int}
    @param recvBuffer: Default receive buffer to be used with
        interface. This attribute may move to machine attribute
        if it turned out to be a platform dependent rather than
        interface dependent.
        This variable is currently dummy.
           
    @type networkId: C{str} or C{int}
    @param networkId: The id of the network at which the interface
        is connected to. Interfaces at the same network can see
        each other. If no value is specified then the interface
        belongs to the 'internet' network. This feature is not
        fully supported yet.
    '''
   
    def __init__ (self, ip, machine, upBand = 0, downBand = 0,
                  sendBuffer = 0, recvBuffer = 0,
                  networkId = NetworksManager.defaultNetwork):
        self._ip = ip
        self.owner = machine
        machine.registerInterface(self)
        #If I'm successfully registered with the machine then I can
        # now register myself on the network.
        self._network = NetworksManager.networkCreateOrAppend(networkId,
                                                               self)
       

    def getOwner(self):
        '''
        Get the L{Machine} that the interface attached to.
       
        @rtype: L{Machine}
        @return: Machine the interface attached to.
        '''
        return self.owner
   
    def getNetworkId(self):
        '''
        Return the network id that the interface belongs to.
       
        @rtype: C{str} or C{int}
        @return: The id of the network that the interface belongs
            to.
        '''
        return self._network.getNetworkID()
   
    def getIp(self):
        '''
        Return the IP of the interface.
       
        @rtype: C{str}
        @return: The IP of the interface.
        '''
        return self._ip


    def pushMsg(self, message):
        '''
        This method shouldn't be called by user.
        
        The method is called when a new message is directed
        to some socket bound to the interface.
        '''
        machine = self.getOwner()
        machine.pushNetworkMsg(message)
    
    def send(self, message):
        '''
        Shouldn't be called by user. The method is called by its owning
        machine in order to send a message through the interface's network.  
        '''
        self._network.send(message)
        

    def sendConnRefused(self, refusedMessage):
        '''
        Shouldn't be called by the user. The method helps the machine to
        refuse a connection that arrived through this interface.
        '''
        self._network.sendConnRefused(self.getIp(), refusedMessage)


class _MachineNetworkMixin():
    '''
    This class is designed to be used as a mixin class with
    L{twistedSim.simManager.Machine}. The class handles the
    network related part for the machine.
    '''
    
    def __init__(self):
        #self._sktModuleMapping = {}
        self._modulesAddrs = {}#The IP addresses that each 
                               # module sockets' reserved.
        self._interfaces = []
        self._skts = {}
        localhost = IpInterface(ip = '127.0.0.1', machine = self,
                                networkId = 'localhost')

        

    def registerInterface(self, ipInterface):
        '''
        The method associates an IpInterface with a machine and
        register it on network.
       
        This method shouldn't be called by user, it's rather
        called by IpInterface constructor.
       
        @type ipInterface: L{IpInterface}
        @param ipInterface: The interface instance to be attached
            to the machine and to be registered on network.
        '''       
        #do more checks here
        self._interfaces += [ipInterface]
        ip = ipInterface.getIp()
        self._skts[ip] = {}
        for sktType in SocketUtil.SocketsSupported:
            self._skts[ip][sktType] = {}
        
       
    def setInterfaceStatus(self, ip, flag, time = None):
        '''
        Enable or disable an IpInterface on the current Machine.
       
        The method is currently dummy.
       
        @type ip: C{str}
        @param ip: A valid ip string
       
        @type flag: C{bool}
        @param flag: C{True} will enable the interface, C{False}
                will disable the interface.
       
        @type time: C{float}
        @param time: The time to put the interface down, if time
            has a value of None then the current time will be used.
        '''
        raise NotImplementedError("not implemented")
        if time == None:
            time = time.time()
       
   
    def _getInterfaces(self):
        '''
        Returns the interfaces instances attached to the machine.
       
        @rtype: C{list} of L{IpInterface}
        @return: The IpInterfaces attached the machine.
        '''
        return self._interfaces


            
    def pushNetworkMsg(self, message):
        '''
        Receives a message and forward it to its appropriate owner,
        if an owner doesn't exist then the method sends a connection
        refused message.
        
        When an IP Interface receives a message, it calls this function
        to hand the received message to its machine (i.e. this class 
        instant). 
        '''
        dstIP, dstPort = message.getDstAddr()
        sktType = message.getSocketType()
        self._setCurrentMachine(self)

        if dstIP in self._skts and dstPort in self._skts[dstIP][sktType]:
            skt = self._skts[dstIP][sktType][dstPort]
            module = self._modules[skt.getOwnerID()]
            from twistedSim.simManager import Module
            Module._setCurrentModule(module)
            skt.pushCMS(message)
            module.ImmediateScheduleRaise()
        else:
            self.refuseConnection(message)
    
    def refuseConnection(self, refusedMessage):
        '''
        Used by a socket or by the machine to refuse an incoming
        connection.
        '''
        dstIP, dstPort = refusedMessage.getDstAddr()
        sktType = refusedMessage.getSocketType()
        for interface in self._getInterfaces():
            if interface.getIp() == dstIP:
                interface.sendConnRefused(refusedMessage)
                return
        else:
            raise RuntimeError("Shouldn't reach here, wrong message" +
                               " forwarded to this machine.")
        
    def registerAddress(self, address, skt):
        '''
        Register an address on this machine with an IP.
        '''
        ip, port = address
        
        try:
            ipSkts = self._skts[ip]
        except KeyError:
            raise ValueError("Don't Own IP")
        else:
            if port in ipSkts[skt.type]:
                raise ValueError("Port already reserved")
            else:
                ipSkts[skt.type][port] = skt
                self._modulesAddrs[skt.getOwnerID()][skt.type].append(address)
    
    def getInterfacesIP(self):
        '''
        Returns a list of the IPs that the machine has.
        '''
        return map(lambda interface: interface.getIp(), self._interfaces)
    
    def isSocketExist(self, ip, _type, port):
        '''
        Used by socket (or a network emulation component) to know whether
        a socket exists or not.
        '''
        return port in self._skts[ip][_type]


    def networkSend(self, sendingInterfaceIP, message):
        '''
        Used by a socket to send a message across the network.
        The sending socket should provide the IP of the IP interface
        (that exists on this simulation machine) that will be used
        to send the message through.
        '''
        if sendingInterfaceIP not in self.getInterfacesIP():
            raise ValueError("Non-existing IP specified in sending.")
        else:
            interface = filter(
                        lambda intrfc: intrfc.getIp() == sendingInterfaceIP,
                        self._interfaces)[0]
        interface.send(message)

    
    def getRandomPort(self, IP, sktType):
        '''
        Get a random port number available on the given IP.
        
        @type IP: C{str}
        @param IP: The IP being looked up, Only IP should be passed
            (not a hastname).
        '''
        interfacesIP = self.getInterfacesIP()
        if not interfacesIP or (IP != '' and IP not in interfacesIP):
            raise SocketErrors.dontOwnAddress

        winnerExists = False    
        while 1: #TODO: I should detect if i used all the available ports
            #TODO: Get the exact ports range
            port = portGenerationRndmProfile.randint(1000,60000) 
            if IP == '': #Bind on all interfaces
                winner = True
                for _IP in interfacesIP:
                    if self.isSocketExist(_IP, sktType, port):
                        winner = False
                        break
                if winner:
                    return port
            else:
                if not self.isSocketExist(IP, sktType, port):
                    return port

class _proxyMachineNetwork:    
    def executeRemote(methodName, args = [], kargs = {}):
        pass
    executeRemote = staticmethod(executeRemote)


class _socketRep():
    '''
    A light weight class that represents a socket.
    
    This class is used in process based simulation. Each object of this
    class represents a socket object. However it is lieht weight so it 
    can be sent faster (and with no pickling problems) over the pipes.
    '''
    def __init__(self, sktType, ownerID, machine = None):
        self.type = sktType
        self._ownerID = ownerID
        self._machine = machine
    
    def pushCMS(self, message):
        '''
        Call by the owning machine when it receives a network message sent 
        to this socket.
        
        This socket representative forwards the message to the socket that
        it represents.
        '''
        if self._machine:
            self._machine._sktPushCMS(message)
        else:
            raise RuntimeError("Wrong method callled.")
            
    def getOwnerID(self):
        '''
        Returns the ID of the owning application.
        
        @rtype: Usually C{int}
        '''
        return self._ownerID
    

class MasterNode():
    '''
    When Process-based emulation used, this class represents part of
    the simManager.Machine on the master node side. 
    
    For an emulated process-based application instance, this class
    represents the proxy between the actual simManger.Machine
    that the emulated application is running on the master node side
    and the EmulatedNode class on the emulated instace's process.
    '''
    
    _portRaneStart = 1000
    _portRangeIncrements = 2000
    
    def initializeMasterNode(self, machine, module):
        '''
        machine: The actual machine that this object is representing.
        '''
        self._portCurrent = MasterNode._portRaneStart
        self._machine = machine
        self._module = module
        return self

    def _sktPushCMS(self, message):
        '''
        Push a network message coming to a socket on the remote machine.
        '''
        self._module.executeRemote("pushNetworkMsg", [message])
    
    def networkSend(self, sendingInterfaceIP, message):
        '''
        Receive from the emulated node a networkSend()
        message. 
        '''
        try:
            self._machine.networkSend(sendingInterfaceIP, message)
        except ValueError:
            raise NotImplementedError("Didn't implement raising error" +
                                      " on remote node yet (1).")

    def registerAddress(self, address, skt):
        '''
        Try to register a socket with a given address.
        
        This method is called by a socket when it tries to bind an address.
        '''
        try:
            self._machine.registerAddress(address, skt)
        except ValueError:
            raise NotImplementedError("Didn't implement raising error" +
                                      " on remote node yet (2).")
    
    def refuseConnection(self, refusedMessage):
        '''
        When a socket refuses a message, it calls this method
        to refuse it.
        '''
        self._machine.refuseConnection(refusedMessage)
    
    def _updateSktMappingIn(self, mapping, moduleId):
        '''
        Receives updates from EmulatedNode._updateSktMappingIn() method.
        The method will send its new mapping state. 
        '''
        for ip in self._machine.getInterfacesIP():
            for _type in SocketUtil.SocketsSupported:
                #First remove the addresses that the remote process
                # unbound.
                for port, skt in self._machine._skts[ip][_type].items():
                    if skt.getOwnerID() == moduleId:
                        #Check if the port is still bound in the
                        # applications mapping
                        if port not in mapping[ip][_type]:
                            #The port no longer exists, then it is unbound
                            # on the remote application. Remove it from 
                            # here as well
                            del self._machine._skts[ip][_type][port]
                        else:
                            #It does exist.
                            #Delete it from the mapping so we can know
                            # later what new addresses has the remote 
                            # application binded on.
                            del mapping[ip][_type][port]
                #Now, let us add all the new addresses that the remote
                # process has added.
                for port, skt in mapping[ip][_type].items():
                    emuSkt = _socketRep(skt.type, moduleId, self)
                    self._machine.registerAddress((ip,port), emuSkt)
    
    def _updateSktMappingOut(self):
        '''
        Calls _updateSktMappingIn on the remote machine.
        '''
        repSkts = {}
        for ip in self._machine._skts:
            repSkts[ip] = {}
            for _type in SocketUtil.SocketsSupported:
                repSkts[ip][_type] = {}
                for port, skt in self._machine._skts[ip][_type].items():
                    repSkts[ip][_type][port] = _socketRep(skt.type,
                                                  skt.getOwnerID())
        self._module.executeRemote("_updateSktMappingIn",
                                   [repSkts])
        

    def getPortRange(self):
        '''
        Return a range of available ports that an emulated process can
        start reserving from without getting back to its owning machine.
        
        This method is a semi-dummy method.
        '''
        _range = (self._portCurrent, self._portCurrent +
                        MasterNode._portRangeIncrements)
        self._portCurrent += MasterNode._portRangeIncrements
        return _range

class EmulatedNode():
    '''
    This class contains that network code that will be executed on the
    emulated node side.
    
    The class also acts as the simManager.Machine but on the emulated
    application process.
    '''
    
    def __init__(self, interfacesIP, sktMapping, portRange, machineName,
                  executeRemote):
        self._interfacesIP = interfacesIP
        self._skts = sktMapping
        self._portRangeStart, self._portRangeEnd = portRange
        self._name = machineName
        self._executeRemote = executeRemote
    
    def _requestMorePorts(self):
        raise NotImplementedError("More ports request is not implemented")

    def _updateSktMappingIn(self, mapping):
        #In the future we might just send the difference in IPs, for
        # now we will just send the whole socket mapping.
        moduleID = _getCurrentModule().getId()
        for ip in self._skts:
            for _type in SocketUtil.SocketsSupported:
                for port, skt in mapping[ip][_type].items():
                    if skt.getOwnerID() != moduleID:
                        self._skts[ip][_type][port] = \
                            _socketRep(skt.type, skt.getOwnerID())
                    elif port not in self._skts[ip][_type]:
                        #If it is that I've created then for sure 
                        #I already have it.
                        raise RuntimeError("Corrupter data sent???")


    def _updateSktMappingOut(self):
        '''
        Just send my sockets that I've bound on.
        '''
        module = _getCurrentModule()
        repSkts = {}
        for ip in self._skts:
            repSkts[ip] = {}
            for _type in SocketUtil.SocketsSupported:
                repSkts[ip][_type] = {}
                for port, skt in self._skts[ip][_type].items():
                    if skt.getOwnerID() == module.getId():
                        repSkts[ip][_type][port] = _socketRep(skt.type,
                                                        skt.getOwnerID())
        self._executeRemote("_updateSktMappingIn", [repSkts, module.getId()])
                
                    
    def registerInterface(self):
        raise NotImplementedError("Not implemented.")
    
    def setInterfaceStatus(self, ip, flag, time = None):
        raise NotImplementedError("Not implemented(2).")
    
    def pushNetworkMsg(self, message):
        dstIP, dstPort = message.getDstAddr()
        sktType = message.getSocketType()

        if dstIP in self._skts and dstPort in self._skts[dstIP][sktType]:
            skt = self._skts[dstIP][sktType][dstPort]
            skt.pushCMS(message)
            module = _getCurrentModule()
            module.ImmediateScheduleRaise()
        else:
            self.refuseConnection(message)
    
    def refuseConnection(self, refusedMessage):
        '''
        Used by a socket (or CMS) to refuse an incoming connection.
        '''
        dstIP, dstPort = refusedMessage.getDstAddr()
        sktType = refusedMessage.getSocketType()
        for interfaceIP in self._getInterfacesIP():
            raise NameError("Forward to remoteProxe refuseConnection")
            if interfaceIP == dstIP:
                self._executeRemote("refuseConnection", refusedMessage)
                return
        else:
            raise ValueError("Shouldn't reach here, wrong message" +
                                        " forwarded to this machine.")

    def registerAddress(self, address, skt):
        '''
        Register an address on this remote machine with an IP.
        '''
        ip, port = address            
        try:
            ipSkts = self._skts[ip]
        except KeyError:
            raise ValueError("Don't Own IP")
        else:
            if port in ipSkts[skt.type]:
                raise ValueError("Port already reserved")
            else:
                ipSkts[skt.type][port] = skt

    
    def getInterfacesIP(self):
        '''
        Returns all the L{IpInterface}s that are attached to this machine.
        '''
        return copy(self._interfacesIP)
    
    def isSocketExist(self, ip, _type, port):
        return port in self._skts[ip][_type]
    
    def networkSend(self, *args, **kargs):
        self._executeRemote("networkSend", args, kargs)


    
    def getRandomPort(self, IP, sktType):
        '''
        Get a random port number available on the given IP.
        
        @type IP: C{str}
        @param IP: The IP being looked up, Only IP should be passed
            (not a hastname).
        '''
        interfacesIP = self.getInterfacesIP()
        if not interfacesIP or (IP != '' and IP not in interfacesIP):
            raise SocketErrors.dontOwnAddress

        winnerExists = False    
        while 1: #TODO: I should detect if i used all the available ports
            #TODO: Get the exact ports range
            port = portGenerationRndmProfile.randint(self._portRangeStart,
                                                     self._portRangeEnd) 
            if IP == '': #Bind on all interfaces
                winner = True
                for _IP in interfacesIP:
                    if self.isSocketExist(_IP, sktType, port):
                        winner = False
                        break
                if winner:
                    return port
            else:
                if not self.isSocketExist(IP, sktType, port):
                    return port

    def getMachineName(self):
        return self._name


#class _ModuleNetworkMixin():
#    '''
#    A race condition could happen when sockets are being bound where two
#    Modules hosted on the same machine are running in the same time (in a
#    process based simulation), in such case the 2 Modules could bind on the
#    same socket address as they didn't get each others binding map updates
#    yet.
#    
#    The work around that we will implement later isa is to make the data
#    structure that contains the machine's socket mapping to be a shared
#    object among the processes.
#    '''
#    def __init__(self):
#        self._sktMapping = {}
#        machine = self.getOwner()
#        ips = machine.getIPs()
#        map(lambda x: self._sktsMapping.update(x, {}), ips)
#        for ip in ips:
#            map(lambda sktType: self._sktMapping[ip].update(sktType),
#                SocketUtil.SocketsSupported)
#        
#        self._fdMapping = {}
#        self._currentFileno = 1
#
#    def bind(self, sktType, addr, sktObject):
#        '''Shouldn't be called by the user'''
#        machine = self.getOwner()
#        machine.bind(sktType, addr, self)
#        self._sktMapping[addr[0]][sktType][addr[1]] = sktObject
#    
#    
#    def unbind(self, sktType, addr):
#        '''Shouldn't be called by the user'''
#        machine = self.getOwner()
#        machine.unbind(sktType, addr)
#        del self._sktMapping[addr[0]][sktType][addr[1]]
#
#    def updateMapping(self, changesMap):
#        '''
#        Called by owing machine to update this Module with the new changes in
#        the socket mapping: which sockets are bound now and which are free
#        now (due to changes made by the other modules running on the same
#        machine).
#        
#        The machine will not send to us the changed that we made.
#        '''
#        for sktType, (ip, port), status in changesMap:
#            #If status is True then this socket has been bound by some other
#            # module running on the same machine, if false then it has been 
#            # unbound.
#            if status: 
#                self._sktMapping[ip][sktType][port] = None#It's owned by 
#                                                          # another module.
#            else:
#                del self._sktMapping[ip][sktType][port] #Its free now
#            
#        raise NotImplementedError()
#
#    def pushNetworkMsg(self, message):
#        '''Shouldn't be called by the user'''
#        sktType = message.getSocketType()
#        ip, port = message.getReceiverAddr()
#        try:
#            skt = self._sktsMapping[ip][sktType][port]
#        except KeyError:
#            raise RuntimeError("Message wrongly passed.")
#        else:
#            skt.pushMsg(message)
#            self.ImmediateScheduleRaise()
#
#    def networkDie(self):
#        '''Shouldn't be called by the user'''
#        for sktTypeDicts in self._sktMapping.values():
#            for skt in sktTypeDicts.values():
#                if skt: #If it is owned by me
#                    skt.close()
#
#    def createFd(self, sktObject):
#        self._fdMapping[self._currentFileno] = sktObject
#        self._currentFileno += 1
#        
#    def getFdObj(self, fd):
#        return self._fdMapping[fd]
#    
#    def isFdExist(self, fd):
#        return fd in self._fdMapping
#    
#    def getFdAll(self):
#        return self._fdMapping
    


class SocketUtil():
    '''
    A static class that contains functionalities that sockets need.
    '''
    
    
    '''
    An easy access to socket types, also provides socket types as 
    strings.
    '''
    SocketType  = { originalSocket.SOCK_DGRAM    :"SOCK_DGRAM",
                    originalSocket.SOCK_RAW      :"SOCK_RAW",
                    originalSocket.SOCK_RDM      :"SOCK_RDM",
                    originalSocket.SOCK_SEQPACKET:"SOCK_SEQPACKET",
                    originalSocket.SOCK_STREAM   :"SOCK_STREAM"}
    
    
    '''
    Socket types that are supported are stored here.
    '''
    SocketsSupported = [originalSocket.SOCK_STREAM,originalSocket.SOCK_DGRAM]
    
    '''
    The send delays for to be used in sending. Each is a tuple of 
    the send delay and its standard deviation.
    '''
    SendDelays = simConfig.Network.SendDelays
      

    def isTypeSupported(sockType):
        ''' 
        Check if socket type is supported.
        
        @type sockType: L{SocketUtil.SocketType} key
        @param sockType: A valid socket type.
        '''
        if sockType in SocketUtil.SocketsSupported:
            return True
        elif sockType in SocketUtil.SocketType.keys():
            raise "Simulation doesn't support "+ \
                    + SocketUtil.SocketType[sockType] +" Socket type yet"
        else :
            return False
    isTypeSupported = staticmethod(isTypeSupported)

    def typesSupported():
        '''
        Returns a list of supported types
        
        @rtype: C{list} 
        @return: L{SocketUtil.SocketsSupported}
        '''
        return SocketUtil.SocketsSupported
    typesSupported = staticmethod(typesSupported)
    
    
#    def _proxySend(sendingSkt, message, delay):
#        
#        methodName = "_sendMsg"
#        sktAddrs = []
#        for interface in sendingSkt.getInterfaces():
#            sktAddrs.append((interface.getNetworkId(), interface.getIP()))
#        
#        args = [dstAddress,
#                sendingSkt._port,
#                sendingSkt.type, 
#                message, 
#                delay, 
#                sktAddrs]        
#        _proxy.executeRemote(methodName, args, {})
#    _proxySend = staticmethod(_proxySend)
#    
#    def _handleRemoteSend(args):
#        '''
#        This function is called on the master node to handle a message
#        coming through the SocketUtil._proxySend() on a remote process.
#        '''
#        dstAddress = args[0]
#        sendingSktPort = args[1]
#        sendingSktType = args[2]
#        message = args[3]
#        delay = args[4]
#        sktAddrs = args[5]
#        
#        receiverIp, receiverPrt = dstAddress
#        #Find the interface that can reach the receiver IP
#        interfaces = map(lambda x: SocketUtil.network[x[0]][x[1]], sktAddrs)
#        foundRoute = False
#        for interface in interfaces:
#            if SocketUtil.isVisibleIp(interface, receiverIp):
#                foundRoute = True
#                senderInterface = interface
#                break
#        
#        if not foundRoute:
#            #Send sender back destination unreachable or whatever appropriate
#            #    error
#            raise "Simulation: Destination not found: "+receiverIp+":" + str(receiverPrt)
#        
#        senderPort = sendingSktPort
#        sockType = sendingSktType
#        
#        #Should i force Sender address here??
#        message.setSenderAddr((senderInterface.getIp(), senderPort))
#        message.setSenderInterface(senderInterface)
#        
#        #Schedule a send in the future
#        if delay == None:
#            if receiverIp == '127.0.0.1':
#                delay, stdDev = SocketUtil.SendDelays[receiverIp]
#            else:
#                delay, stdDev = SocketUtil.SendDelays[sockType]
#        
#        if not simConfig.Network.fixedSendDelay:
#            delay = sendDelayRndmProfile.gauss(delay,stdDev)
#            delay = abs(delay) #It could yield in negative values
#            
#        Scheduler.enqueue(delay, SocketUtil._sendHandler,
#                          (receiverIp, receiverPrt), sockType,
#                          message)
#    _handleRemoteSend = staticmethod(_handleRemoteSend)
        
    
    

class centralMessageeStorage():
    '''
    This class stores messages for a socket address. It's main use is with
    L{_serverSocket} that has L{_peerSocket}s attached with it on the
    same IP,Port.
    
    L{_peerSocket}s are created as a result of L{_serverSocket.accept}().
    These sockets have the same IP,Port address as their creating socket 
    address. When a message arrives to that address it's yet known if 
    it's for the L{_serverSocket} or for one of it's  L{_peerSocket}s, 
    therefore incoming messages need to be saved first in a central 
    storage shared between the L{_serverSocket} and it's L{_peerSocket}s.
    When any of these sockets is active, it should enquiry for the 
    messages waiting for it by itself.
    
    Every L{_serverSocket} should own an object of this class and should
    share it with it's inheriting L{_peerSocket}s objects
    '''
    def __init__(self):
        self._waitingMsgs = {}
    
    def addSocket(self, remoteAdd, sockObject):
        '''
        Add ibe sicjet
        '''
        self._waitingMsgs[remoteAdd] = sockObject

    def removeSocket(self, remoteAddr):
        del self._waitingMsgs[remoteAddr]
        
    def isSocketExist(self, remoteAddr):
        return remoteAddr in self._waitingMsgs

    
    def addServer(self, sockObject):
        '''
        This method is called when we want to create an entry for a 
        server socket or when a UDP socket is used.
        
        All new connections will be forwarded to that socket.
        '''
        self.addSocket(0, sockObject)
        
    def removeServer(self):
        return self.removeSocket(0)
    
    def isServerExist(self):
        return self.isSocketExist(0)
    
    def pushMsg(self, message):
        addr = message.getSenderAddr()
        if addr in self._waitingMsgs:
            self._waitingMsgs[addr].pushMsg(message)
        elif 0 in self._waitingMsgs: #If yes then there is a server socket 
                                     # that handles new connections.
           self._waitingMsgs[0].pushMsg(message)
        else:
            machine = _getCurrentMachine()
            machine.refuseConnection(message)




#Overriding starts from here---------

def gethostbyname(hostname):
    ''' 
    An override for C{socket.gethostbyname()} function.
    
    This is a semi-dummy function, It only works with the current
    machine.
    
    @type hostname: C{str}
    @param hostname: The host being looked-up.
    '''
    machine = _getCurrentMachine()
    currentMachineName = machine.getMachineName()
    
    if hostname != currentMachineName and hostname != "localhost":
        raise "Simulation: socket.getHostByname() only works with local machine." +\
              "\nHostname: " + str(hostname) + "x Current Machine Name: " +\
              str(currentMachineName)
    else:
        interfacesIP = machine.getInterfacesIP()
        if len(interfacesIP)  < 2:
            return interfacesIP[0] #Can it be anything other than localhost??
        else:
            return interfacesIP[1]#I return the first available interface.



def gethostname():
    '''
    An override for C{socket.gethostname()}
    
    This function is half-dummy. Later: if the function found that
    the machine has no name then it should return the appropriate 
    IP.
    '''
    machine = _getCurrentMachine()
    return machine.getMachineName()


def _hookMethods(dstObj, srcObj):
    '''
    This method hooks the callable methods of srcObj to the dstObj.
    
    E.g.:
    class A:
        def i(self):
            print "a"
    
    
    class B:
        def j(self):
            print "b"
    
            
    x = A()
    y = B()
    
    _hookMethods(x, y)
    x.j()
    #The previous call will work normally and will print "b"
    '''
    #Get the destination object's entities names.
    entitiesNames = dir(srcObj) 
    #Afterwards get the destination object's entities themselves
    entities = map(lambda name: getattr(srcObj, name), entitiesNames)
    #Associate the entities names with the entities themselves
    allE = zip(entities, entitiesNames)
    #Filter away all non-callable entities and leave only the callables
    methods = filter(lambda x: callable(x[0]),allE)
    #Take these callables and attach them as if they are part of srcObject
    map(lambda method: setattr(dstObj, method[1], method[0]), methods)



def _hookAttrs(dstObj, srcObj):
    #Get the destination object's entities names.
    entitiesNames = dir(srcObj) 
    #Afterwards get the destination object's entities themselves
    entities = map(lambda name: getattr(srcObj, name), entitiesNames)
    #Associate the entities names with the entities themselves
    allE = zip(entities, entitiesNames)
    #Filter away all non-callable entities and leave only the callables
    methods = filter(lambda x: not callable(x[0]),allE)
    #Take these callables and attach them as if they are part of srcObject
    map(lambda method: setattr(dstObj, method[1], method[0]), methods)





class _SocketOverride():
    '''
    A wrapper around L{_serverSocket}. The class role is to monitor
    the referencing of the socket and initiate its disconnect 
    message to the other party.
    '''    
    
    def __init__(self, family, sktType, porto = 0):
        #self._referenceCount = 8
        if SocketUtil.isTypeSupported(sktType):
            if sktType == originalSocket.SOCK_STREAM:
                skt = _TCPSocket(family, sktType, porto, self)
            elif sktType == originalSocket.SOCK_DGRAM:
                skt = _UDPSocket(family, sktType, porto)
            _hookMethods(self, skt)
        else:
            raise SocketErrors.socketTypeNotSupported

class _SocketCommon(_SocketOverride):
    '''
    Class that contains similar methods that are used in the same
    way by both TCP and UDP classes. 
    '''
    
    def __init__(self, family, sktType, proto):
        self._setMyOwner()
        module = _getCurrentModule()
        self._fileno = module.createFileDesc(self)
        self._interfacesIP = []
        self._ip = None
        self._bound = False
        self.family = family
        self.type = sktType
        self.proto = proto
        
    
    def _setMyOwner(self):
        self._ownerID = _getCurrentModule().getId()
    
    def bind(self, address):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        if self._isBound():
            raise SocketErrors.alreadyBound
        
        try:
            ip , port = address
        except Exception,e: #TODO: Check what type of  error i should catch
            #Catch for each socket type
            raise TypeError('getsockaddrarg: AF_INET address must be' + 
                            ' tuple, not '+ type(address) +"'",)
            
        machine = _getCurrentMachine()
        if port == 0:
            port = machine.getRandomPort(ip, self.type)
            address = ip, port
            
        if ip == '':
            #Find an available port on all the interfaces 
            for ip in machine.getInterfacesIP():
                    self._bindToInterface((ip, port))
            self._ip = '0.0.0.0'
            self._port = port
        elif isIPAddress(ip) or ip == 'localhost':
            if ip == 'localhost':
                ip = '127.0.0.1'
            self._bindToInterface((ip,port))
        else:
            raise NotImplementedError("TwistedSim: doesn't support name" +
                                      " resolution yet")       
        self._bound = True
    
    def _bindToInterface(self, address):
        '''
        Bind one port to one interface, 
        only takes ip and port.
        
        @type address: (C{str},C{int})
        @param address: A tuuple of (IP,Port), IP can't be
            empty string or localhost
        '''
        IP, port = address
        myMachine = _getCurrentMachine()
        if IP in myMachine.getInterfacesIP():
            myMachine.registerAddress(address, self)
            self._ip = IP
            self._interfacesIP += [IP]
            self._port = port
            return
        else:
            raise SocketErrors.dontOwnAddress


    def _isBound(self):
        return self._bound
    
    def connect_ex(self, address):
        '''Emulates the socket method that has the same name.'''
        try:
            self.connect(address)
        except Exception,e:
            import sys
            import traceback
            return e[0] #All errors are tuples, return error number


    def getsockname(self):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        if self._ip != None:
            return (self._ip, self._port)
        else:
            raise SocketErrors.invalidArgument
    

    def getsockopt(self,level, optname):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()    
        if level not in self.sockOpts:
            raise NotImplementedError("TwistedSim: Unsupported sockopt" +
                                      " level requested:" + str(level) + 
                                      "  with optname: " + str(optname))
        if optname not in self.sockOpts[level]:
            raise NotImplementedError("TwistedSim: Unsupported sockopt" +
                                      " optname requested at level:" + 
                                      str(level) + " and optname: " + 
                                      str(optname))
        return self.sockOpts[level][optname]

    def gettimeout(self):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: unimplemented " +
                                  " gettimeout() called")

    def fileno(self):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        return self._fileno
    
    def ioctl(self, control, option):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: unimplmented iotcl() called")
    
    def makefile(self, mode, bufsize):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: unimplmented makefile()" +
                                  " called")

    
    def recvfrom_into(self, bufsize, nbytes, flags = 0):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: unimplmented" +
                                  " recvfrom_into() called")
    
    def recv_into(self, bufsize, nbytes, flags = 0):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: unimplmented recv_intro()" +
                                  " called")
    
    def sendall(self, string, flags = 0):
        '''Emulates the socket method that has the same name.'''
        self.send(string, flags)
        Warning("this is a sendall hack")
        
    def setblocking(self, flag):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()    
        #For now, I won't accept any values except 1 and 0 until I know
        # really how other values work/
        if flag == 0:
            self._blocking = 0
        elif flag == 1:
            self._blocking = 1
        else:
            NotImplementedError("TwistedSim: flag value is not" +
                                " implemented: " + str(flag)) 
            
    
    def _getBlocking(self):
        return  self._blocking
    
    def settimeout(self,value):
        #self._checkSockStatus()    
        raise NotImplementedError("TwistedSim: unimplemented " +
                                   "settimeout() called")

        
    def _reallySend(self, message):
        '''The function performs the actual sending'''
        #Should i handle blocking and non-blocking here??
        dstIp, dstPort = message.getDstAddr()
        if dstIp == 'localhost':
            dstIp = '127.0.0.1'

        sendingInterfaceIP = self._getVisibleRoute(dstIp)
        if not sendingInterfaceIP or sendingInterfaceIP not in self._interfacesIP:
            raise SocketErrors.unreachable
        
        message.setSenderAddr((sendingInterfaceIP, self._port))
        machine = _getCurrentMachine()
        machine.networkSend(sendingInterfaceIP, message)
        
    def _checkSockStatus(self):
        '''
        Check if socket is active or closed.
        '''
        if self._destroyed:
            self._raiseSocketError(SocketErrors.badDescriptor)
            

    def _raiseSocketError(self, error):
        self.sockOpts[originalSocket.SOL_SOCKET][originalSocket.SO_ERROR] = error
        raise error
                     
    
    def _getVisibleRoute(self, ip):
        '''
        Get the interface that can reach an requested IP, If 
        several interfaces have an access, then the first one
        found will be returned.
        
        This method is half-dummy, It doesn't really look for
        the route, It just returns loopback interface if the
        IP was localhost, And any other interface otherwise.
        
        @type ip: C{str}
        @param ip: The ip bieng is looked up.
        '''
        #TODO: Create route table to know which IP Interface to use.
        machine = _getCurrentMachine()
        if ip == '127.0.0.1' or ip == 'localhost':
            for interfaceIP in machine.getInterfacesIP():
                if interfaceIP == '127.0.0.1':
                    return interfaceIP
            else:
                return False
        else:
            import warnings
            warnings.warn("Blah Blah, check my interface instead")
            warnings.warn("Can't look route in bound IPs as sometimes the" + 
                          "method is used to look for interfaces to bound on.")
            for interfaceIP in machine.getInterfacesIP():
                #This is the dummy part
                if interfaceIP != '127.0.0.1':
                    return interfaceIP
            else:
                return False
        
    def getInterfacesIp(self):
        '''
        Return the interfaces that the socket is bound to.

        @rtype: C{List} L{simManager.IpInterface}
        @return: The list of IP interfaces that the socket is bound
        to.
        '''
        return copy(self._interfacesIP)
    

    def pushCMS(self, message):
        self._CMS.pushMsg(message)


    def getOwnerID(self):
        '''
        Return the Module object that this socket is created on.
        '''
        return self._ownerID

class _UDPSocket(_SocketCommon):
    
    def __init__(self, family, type, proto):
        _SocketCommon.__init__(self, family, type, proto)
        
        self._blocking = True
        self._messages = []
        self._destroyed = False
        self._remoteAddr = None
        self._CMS = centralMessageeStorage()
        self._CMS.addServer(self)
        self._createSockOpts()
    
    def _createSockOpts(self):
        self.sockOpts = {originalSocket.SOL_SOCKET:{},
                    originalSocket.IPPROTO_TCP:{},
                    originalSocket.IPPROTO_IP:{}}
        
        self.sockOpts[originalSocket.SOL_SOCKET] = {
                                               originalSocket.SO_ERROR:0
                                               #No errors yet 
                                               }   
    
    def close(self):
        '''Emulates the socket method that has the same name.'''
        if self._destroyed:
            return 
        self._destroyed = True
        self._CMS.removeServer()
    
    
    def connect(self, address):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
                
        if not self._isBound():
            interfaceIP = self._getVisibleRoute(address[0])
            self.bind((interfaceIP, 0)) 
                              
        #Check for the validity of the address (format wise).
        self._remoteAddr = address #In UDP (unlike TCP) the User can
                                   # call connect() many times.

    def getpeername(self):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        if self._remoteAddr:
            return self._remoteAddr
        else:
            raise SocketErrors.socketNotConnected
    
    def recvfrom(self, bufsize, flags = 0):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        
        if flags != 0:
            raise NotImplementedError("TwistedSim: flags  not supported yet")
        
        if not isinstance(bufsize, int):
            raise SocketErrors.integerRequired
        
        if not self._messages:
            if self._blocking:
                raise NotImplementedError("TwistedSIm: Blocking sockets" +
                                          " are not supported")
            else:
                raise SocketErrors.nothingToReceive
        else:
            msg = self._messages.pop(0)
            data = msg.getData()
            senderAddr = msg.getSenderAddr()
            if len(data) > bufsize:
                raise SocketErrors.messageTooLong
            return data, senderAddr
        

    def recv(self, bufsize, flags = 0):
        '''Emulates the socket method that has the same name.'''
        #TODO: Make sure that receiving is not only
        # restricted to remote address (make the check
        # across different OSes).
        return self.recvfrom(bufsize, flags)[0]
    
    def sendto(self, string, address, flags = 0):
        '''Emulates the socket method that has the same name.''' 
        self._checkSockStatus()
        
        #Check that "string" is of string type or read only buffer.
        #Check that string length is as long as permitted.
        #Check that address is a well formed tuple.
    
        #Send could block if the send buffer is full.
        if 1: 
            if type(string) == buffer:
                #Buffer objects are not pickleable and we cannot send
                # them through multiprocessing.pipe()
                string = str(string)
            msg = socketMessage(address, messageTypes.Data,
                                 self.type, string)
            self._reallySend(msg)
            return len(string)
    
    
    def send(self, string, flags = 0):
        '''Emulates the socket method that has the same name.'''
        if not self._remoteAddr:
            raise SocketErrors.socketNotConnected
        else:
            if type(string) == buffer:
                #Buffer objects are not pickleable and we cannot send
                # them through multiprocessing.pipe()
                string = str(string)
            return self.sendto(string, self._remoteAddr, flags)
       

    def shutdown(self,how):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: Unimplemented UDP" +
                                  " shutdown() method.") 
    
    def pushMsg(self, msg):
        self._messages.append(msg)
        
    
    def isNewRead(self):
        if self._messages:
            return True
        else:
            return False

    def isNewWrite(self):
        return True


class _TCPSocket(_SocketCommon):
    
    def __init__(self, family, type, proto, _pSktHack):
        _SocketCommon.__init__(self, family, type, proto)
        self._CMS = centralMessageeStorage()
        self._blocking = True
        self._destroyed = False
        self._listening = False
        self._createSockOpts()
        self._pSktHack = _pSktHack
    
    def _createSockOpts(self):
        '''
        Creat defaullt socket options.
        
        Not all the options are created. This options are grown
        on demand.
        '''
        self.sockOpts = {originalSocket.SOL_SOCKET:{},
                    originalSocket.IPPROTO_TCP:{},
                    originalSocket.IPPROTO_IP:{}}
        
        self.sockOpts[originalSocket.SOL_SOCKET] = {
                                       #No errors yet
                                       originalSocket.SO_ERROR:0, 
                                       originalSocket.SO_REUSEADDR:0
                                       }
    
        self.sockOpts[originalSocket.IPPROTO_TCP] = {
                                        #i.e. Nagle algortihim enabled
                                        originalSocket.TCP_NODELAY:0 
                                        }    
    
        
    def listen(self, backlog):
        '''Emulates the socket method that has the same name.''' 
        self._checkSockStatus()
        
        if type(backlog) != type(1):
            raise SocketErrors.integerRequired
        if not self._isBound():
            raise SocketErrors.invalidArgument    
        #In our tests on certain OS, calling listen() with a different
        # backlog value on an already listening socket has no effect. 
        if not self._listening:
            s = _ServerSocket(backlog, self._getBlocking(), self._CMS)
            _hookMethods(self, s)
            _hookAttrs(s, self)
            _hookMethods(self._pSktHack, self)
            self._listening = True
    
    def connect(self, addr):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        
        if not self._isBound():
            interfaceIP = self._getVisibleRoute(addr[0])
            self.bind((interfaceIP,0)) 
                              
        if self._blocking:
                raise NotImplementedError("TwistedSimd doesn't support" +
                                          " blocking sockets yet")
        else:
            p = _PeerSocket(addr, self.getsockname(), self._getBlocking(), 
                            copy(self._interfacesIP), self._CMS, self.fileno())
            _hookMethods(self, p)
            _hookAttrs(p, self)
            _hookMethods(self._pSktHack, self)
            raise SocketErrors.connectNonBlocking
    
    def send(self, msg, flag = 0):
        '''
        Emulates the socket method that has the same name.
        
        Note that once connect is called successfully, this method will
        be replaced dynamically with _PeerSocket.send()
        '''
        self._checkSockStatus()
        raise SocketErrors.socketNotConnected
    
    
    def recv(self, bufferLength, flag = 0):
        '''
        Emulates the socket method that has the same name.
        
        Note that once connect is called successfully, this method will
        be replaced dynamically with _PeerSocket.recv()
        '''
        self._checkSockStatus()
        if type(bufferLength) != int:
            raise SocketErrors.integerRequired
        raise SocketErrors.socketNotConnected

    def close(self):
        '''Emulates the socket method that has the same name.'''
        if self._destroyed:
            return 
        module = _getCurrentModule()()
        module.removeFileDesc(self.fileno())
        self._destroyed = True
    
    def isNewRead(self):
        return False
    
    def isNewWrite(self):
        return False

class _ServerSocket(_SocketCommon):
    
    def __init__(self, backlog, blocking, CMsgStorage):
        self._backlog = backlog
        self._blocking = blocking
        self._waitingPeers = []
        self._poteinalPeers = {}
        self._CMS = CMsgStorage
        self._CMS.addServer(self)
        self._gracePeriod = 30
        self._destroyed = False
        
    def accept(self):
        '''Emulates the socket method that has the same name.'''
        if self._waitingPeers:
            return self._waitingPeers.pop(0)
        else:
            if self._blocking:
                raise SocketErrors.blockingNotImplemented
            else:#in non-blocking mode
                raise SocketErrors.nothingToAccept
    
    def setblocking(self, flag):
        self._blocking = flag
    
    
    def shutdown(self, how):
        '''
        Emulates the socket method that has the same name.
        Currently dummy. Has no effect.
        '''
        return 
    
    def close(self):
        '''Emulates the socket method that has the same name.'''
        if self._destroyed:
            return 
        
        module = _getCurrentModule()
        module.removeFileDesc(self.fileno())
        
        self._CMS.removeServer()
        self._destroyed = True

     
    def pushMsg(self, msg):
        '''
        User shouldn't call this, not part of original sockets
        '''        
        if len(self._waitingPeers) < self._backlog:
            self._handleNewPeer(msg)
        else: #I'm not listening.
            #send a connection refusal here
            #delete the guyz info here
            raise NotImplementedError("Manage this part")
    
    def _handleNewPeer(self,message):
        '''
        Create a peer socket and do the necessary processing.
        '''
        self._eliminateTimedOut()
        if message.getSeq() != 0:
            #Maybe due to random arrival of packets i got 
            #something else before Handshake_1, so I'll
            #store the message and wait for a Handshake_1
            #to arrive during a certain timeout range, if
            #the timeout expired then the previous data will
            #be canceled.
            senderAddr = message.getSenderAddr()
            if senderAddr not in self._poteinalPeers:
                self._poteinalPeers[senderAddr] = ([message], time.time())
            self._poteinalPeers[senderAddr][0].append(message)
        else:
            msgType = message.getMessageType()
            if msgType != messageTypes.HandShake_1:
                #Someone is fooling around, maybe
                #I'll send connection reset.
                return 
            peerAddr = message.getSenderAddr()
            peerSkt = _PeerSocket(peerAddr, self.getsockname(),
                                  self._blocking, copy(self._interfacesIP),
                                  self._CMS)
            acceptTuple = peerSkt, peerSkt.getpeername()
            self._waitingPeers.append(acceptTuple)

    
    def _eliminateTimedOut(self):
        now = time.time()
        #Bad algorithm
        deleteList = []
        for addr, (ignoreMsgs, inTime) in self._poteinalPeers.items():
            if inTime + self._gracePeriod <= now:
                deleteList.append(addr) 
        map(lambda addr:self._poteinalPeers.__delitem__(addr), deleteList)    


    
    def isNewRead(self):
        self._checkSockStatus()
        if self._waitingPeers:
            return True
        else:
            return False
        

    def isNewWrite(self):
        '''
        Return if the socket is available for writing.
        
        @rtype: C{bool} 
        '''
        return False#Could it be true?


class _PeerSocket(_SocketCommon):

    def __init__(self, remoteAddr, myAddr, blocking, interfacesIP, 
                 CMsgStorage, fdIfConn = None):
        '''
        fdIfConn: The variable is used to deffrentiate between whether this
            socket is created as a result of listening Socket.accept() or 
            as a result of a socket.connect(), if this socket is created as
            a result of an accept() then it should acquire its own new fd.
            If it was created as a result of connect() then it should acquire
            the fd of the socket that created it. 
            
            Hence:
            If fdIfConn is equal None then this socket is created as a result
            of an accept(), it should acquire its own fd and should contine
            trying to establish the connection (by sending handhshake 2).
            
            If this is a connecting server then the value of fdIdCOnn will 
            carry the value of the parent's socket fd, this socket should
            use this value, the socket will be still waiting for connection
            establishment so it should mark it self as still trying to 
            connect.
        '''
        self.family = originalSocket.AF_INET
        self.type = originalSocket.SOCK_STREAM
        self.proto = originalSocket.IPPROTO_TCP
        
        self._interfacesIP = interfacesIP
        self._remoteAddr = remoteAddr
        self._blocking = blocking
        self._buffer = ""
        self._disconnected = False
        self._destroyed = False
        
        self._sortedMsgs = []
        self._unsortedMsgs = []
    
        CMsgStorage.addSocket(remoteAddr, self)
        self._CMS = CMsgStorage

        self._ip, self._port = myAddr
        if fdIfConn: #I'm a socket created a result of socket.connect()
            self._fileno = fdIfConn
            self._seqSend = 0
            self._seqRecv = 0 
            self._tryingToConnect = True
            self._establishConnection(messageTypes.HandShake_1)
            
        else: #I'm a socket that is created as a result of server.accept()
            self._setMyOwner()
            module = _getCurrentModule()
            self._fileno = module.createFileDesc(self)
            self._seqSend = 0
            self._seqRecv = 1 #We already received Handhsake_1
            self._tryingToConnect = False
            self._establishConnection(messageTypes.HandShake_2)
            
    def _establishConnection(self, HSstep):
        replyMsg = socketMessage(self._remoteAddr, HSstep, 
                                 self.type, None)
        self._reallySend(replyMsg)


     
    def connect(self, addr):
        '''Emulates the socket method that has the same name.'''
        raise SocketErrors.socketAlreadyConnected
   
    
    def send(self, string, flags = 0):
        '''Emulates the socket method that has the same name.'''
        if flags != 0:
            raise RuntimeError("Simulation doesn't support flags yet")
        
        self._checkSockStatus()
        
        if self._disconnected:
            raise SocketErrors.socketDisconnected
        
        if self._tryingToConnect:
            raise SocketErrors.socketNotConnected
        
        #Since buffer is not implemented yet, therefore send() will never
        #fail.
        
        if type(string) == buffer:
            #Buffer objects are not pickleable and we cannot send
            # them through multiprocessing.pipe()
            string = str(string)
        message = socketMessage(self._remoteAddr, messageTypes.Data,
                                self.type, string)
        self._reallySend(message)
        return len(string)

    def sendto(self, string, flags, address):
        '''Emulates the socket method that has the same name.'''
        raise NotImplementedError("TwistedSim: unimplemented sendto()")        
    
    
    def recv(self, bufsize, flags = 0):
        '''Emulates the socket method that has the same name.'''
        if flags != 0:
            raise RuntimeError("Simulation doesn't support flags yet")
        
        self._checkSockStatus()
        
        if self._tryingToConnect:
            raise SocketErrors.socketNotConnected
        
        if self._buffer:
            buffLen = min(bufsize, self._buffer)
            data = self._buffer[:buffLen]
            self._buffer = self._buffer[buffLen:]
            return data
        elif self._disconnected:
            raise SocketErrors.socketDisconnected
        else:
            if self._blocking:
                raise SocketErrors.blockingNotImplemented
            else:
                raise SocketErrors.nothingToReceive    
    
    def recvfrom(self, bufsize, flags = 0):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        
        if not isinstance(bufsize, int):
            raise SocketErrors.integerRequired
        
        raise NotImplementedError("TwistedSim: unimplemented recvfrom()")
    
    def getpeername(self):
        '''Emulates the socket method that has the same name.'''
        self._checkSockStatus()
        return self._remoteAddr
    
    
    def shutdown(self, how):
        ''' Semi-dummy, does nothing to the other side '''
        self._checkSockStatus()
        if self._tryingToConnect:
            raise SocketErrors.socketNotConnected
          
        if how == 2:
            self.disconnect()
        else:
            raise NotImplementedError("Another type of disconnection " + 
                                      "required")
        return
    
    
    def disconnect(self):
        '''
        Dosconnects the sockets and inform the other party about
        disconnection.
        '''
        if self._disconnected:
            return
        #TODO: What happens if I'm connecting then tried to disconnect
        # before the connection is established??
        message = socketMessage(self._remoteAddr, messageTypes.Disconnect,
                                self.type, None, self.getsockname())
        self._reallySend(message)
        self._disconnectSelf()
    
    def close(self):
        '''Emulates the socket method that has the same name.'''
        if self._destroyed:
            return 
        self.disconnect()
        
        module = _getCurrentModule()
        module.removeFileDesc(self.fileno())
        
        self._destroyed = True
    
    def pushMsg(self, msg):
        '''
        This method is not part of the original socket implementation
        and shouldn't be called by the user.
        
        The method is called when a new socket directed to this socket
        is received.
        '''
        self._sortMsgs(msg)
        for msg in self._sortedMsgs:
            msgType, data = msg.getMessage()
            senderAddr = msg.getSenderAddr()
            if self._tryingToConnect:
                if self._remoteAddr == senderAddr:
                    #Is he the real sender or someone is bluffing??
                    if msgType == messageTypes.HandShake_2:
                        self._tryingToConnect = False
                    elif msgType == messageTypes.ConnectionRefused:
                        #TODO: Set socket option to the error. 
                        #needs testing, we never reach her because module.die()
                        #kills the module gracefully and disconnect all the 
                        #sockets gracefully. 
                        self._tryingToConnect = False
                        self._disconnectSelf()
                    else:
                        print "Unexpected message type received."
                else:
                    #Someone is bluffing, what should i do???
                    pass
            elif msgType == messageTypes.Disconnect or\
                msgType == messageTypes.ConnectionRefused:
                #Defferntiate later between gracefeil disconnect
                # and ungraceful disconnect.
                #We can get connection refused if the guy we
                #were connected to died.
                #raise "Reduce socket refrence count"
                self._disconnectSelf()
            elif msgType == messageTypes.Data:
                self._buffer += str(data)
            else:
                raise ValueError("Unhandled Message Type")
        self._sortedMsgs = []
    
    def _disconnectSelf(self):
        '''
        Disconnect on my side (this method is not responsible for
        informing the other side about disconnection).
        '''
        if self._disconnected:
            return
        else:
            self._disconnected = True
            self._CMS.removeSocket(self._remoteAddr)
    
    def _sortMsgs(self, msg):
        '''
        Sorts the incoming messages according to their sequence.
        '''
        heappush(self._unsortedMsgs, (msg.getSeq(),msg))
        while self._unsortedMsgs:
            #We want to check to see if the first item in the
            # unsorted messages is actually the next item that
            # should be received or not (maybe the next message
            # that should exist didn't arrive yet and maybe the
            # message after it has arrived).
            # We need to check the heap-sorted messages in the
            # self._unsorted list. The unsorted list is actually
            # sorted (using heap queue algorithm ofcourse) but it holds
            # all the messages that might have arrived event if they 
            # are out of seuquence. The self._sorted messages contains
            # all the messages that arrived but yet in the right order.
            seq, msg = self._unsortedMsgs[0]
            if self._seqRecv  == seq:
                heappop(self._unsortedMsgs)
                self._sortedMsgs.append(msg)
                self._seqRecv += 1
            else:
                return 
            
    def _reallySend(self, message):
        '''
        We don't take a dstAddr here cause we will alawys send to the 
        remotely connected peer only.
        '''
        message.setSeq(self._seqSend)
        _SocketCommon._reallySend(self, message)
        self._seqSend += 1    
    
    def isNewRead(self):
        '''
        The method returns wheter there is a new "reading action" 
        available for the socket.
        '''
        self._checkSockStatus()
        return self._buffer or self._disconnected


    def isNewWrite(self):
        '''
        Return if the socket is available for writing.
        
        @rtype: C{bool} 
        '''
        #"not self._tryingToConnect" means that I've established a 
        # connection (however I might be sill connected or disconnected).
        return not self._tryingToConnect